optimize speed and distance conversions. (#753)
authortsteven4 <13596209+tsteven4@users.noreply.github.com>
Thu, 4 Nov 2021 14:02:09 +0000 (08:02 -0600)
committerGitHub <noreply@github.com>
Thu, 4 Nov 2021 14:02:09 +0000 (08:02 -0600)
* optimize speed and distance conversions.

structure constexpr conversions such that a minimal amount of
arithmetic is done at run time and avoiding run time division.

add tests for conversions.

* correct bug with display of accumulated path distance.

and add test case of same.

13 files changed:
defs.h
reference/distance.csv [new file with mode: 0644]
reference/distance2.csv [new file with mode: 0644]
reference/distance2~csv.csv [new file with mode: 0644]
reference/distance3.csv [new file with mode: 0644]
reference/distance3~csv.csv [new file with mode: 0644]
reference/distance~csv.csv [new file with mode: 0644]
reference/speed.csv [new file with mode: 0644]
reference/speed~csv.csv [new file with mode: 0644]
testo.d/unitconversion.test [new file with mode: 0644]
xcsv.cc
xcsv.h
xmldoc/chapters/styles.xml

diff --git a/defs.h b/defs.h
index 70ee1262abe0cd1f7fabf65b6cc722411dd4b45d..68c14159decf5e530a3125efc66109c9b0ad1ec4 100644 (file)
--- a/defs.h
+++ b/defs.h
@@ -77,40 +77,49 @@ constexpr double kMetersPerMile = 1609.344; /* exact in decimal notation */
 constexpr double kMilesPerMeter = 1.0 / kMetersPerMile;
 constexpr double kKilometersPerMile = 1.609344; /* exact in decimal notation */
 constexpr double kMilesPerKilometer = 1.0 / kKilometersPerMile;
+constexpr double kMetersPerNMile = 1852.0; /* exact in decimal notation */
+constexpr double kNMilesPerMeter = 1.0 / kMetersPerNMile;
 
-constexpr double FEET_TO_METERS(double feetsies) { return (feetsies) * kMetersPerFoot; }
-constexpr double METERS_TO_FEET(double meetsies) { return (meetsies) * kFeetPerMeter; }
+constexpr double FEET_TO_METERS(double feetsies) { return feetsies * kMetersPerFoot;}
+constexpr double METERS_TO_FEET(double meetsies) { return meetsies * kFeetPerMeter;}
 
-constexpr double NMILES_TO_METERS(double a) { return a * 1852.0;}      /* nautical miles */
-constexpr double METERS_TO_NMILES(double a) { return a / 1852.0;}
+constexpr double NMILES_TO_METERS(double a) { return a * kMetersPerNMile;}     /* nautical miles */
+constexpr double METERS_TO_NMILES(double a) { return a * kNMilesPerMeter;}
 
-constexpr double MILES_TO_METERS(double a) { return (a) * kMetersPerMile;}
-constexpr double METERS_TO_MILES(double a) { return (a) * kMilesPerMeter;}
-constexpr double FATHOMS_TO_METERS(double a) { return (a) * 1.8288;}
+constexpr double MILES_TO_METERS(double a) { return a * kMetersPerMile;}
+constexpr double METERS_TO_MILES(double a) { return a * kMilesPerMeter;}
+constexpr double FATHOMS_TO_METERS(double a) { return a * 1.8288;}
 
-constexpr double CELSIUS_TO_FAHRENHEIT(double a) { return (((a) * 1.8) + 32.0);}
-constexpr double FAHRENHEIT_TO_CELSIUS(double a) { return (((a) - 32.0) / 1.8);}
+constexpr double CELSIUS_TO_FAHRENHEIT(double a) { return (a * 1.8) + 32.0;}
+constexpr double FAHRENHEIT_TO_CELSIUS(double a) { return (a - 32.0) / 1.8;}
 
 constexpr long SECONDS_PER_HOUR = 60L * 60;
 constexpr long SECONDS_PER_DAY = 24L * 60 * 60;
 
+constexpr double kKPHPerMPS = SECONDS_PER_HOUR / 1000.0;
+constexpr double kMPSPerKPH = 1.0 / kKPHPerMPS;
+constexpr double kMPHPerMPS = kMilesPerMeter * SECONDS_PER_HOUR;
+constexpr double kMPSPerMPH = 1.0 / kMPHPerMPS;
+constexpr double kKnotsPerMPS = kNMilesPerMeter * SECONDS_PER_HOUR;
+constexpr double kMPSPerKnot = 1.0 / kKnotsPerMPS;
+
 /* meters/second to kilometers/hour */
-constexpr double MPS_TO_KPH(double a) { return (a)*SECONDS_PER_HOUR/1000.0;}
+constexpr double MPS_TO_KPH(double a) { return a * kKPHPerMPS;}
 
 /* meters/second to miles/hour */
-constexpr double MPS_TO_MPH(double a) { return METERS_TO_MILES(a) * SECONDS_PER_HOUR;}
+constexpr double MPS_TO_MPH(double a) { return a * kMPHPerMPS;}
 
-/* meters/second to knots */
-constexpr double MPS_TO_KNOTS(double a) { return MPS_TO_KPH((a)/1.852);}
+/* meters/second to knots(nautical miles/hour) */
+constexpr double MPS_TO_KNOTS(double a) { return a * kKnotsPerMPS;}
 
 /* kilometers/hour to meters/second */
-constexpr double KPH_TO_MPS(double a) { return a * 1000.0/SECONDS_PER_HOUR;}
+constexpr double KPH_TO_MPS(double a) { return a * kMPSPerKPH;}
 
 /* miles/hour to meters/second */
-#define MPH_TO_MPS(a) (MILES_TO_METERS(a) / SECONDS_PER_HOUR)
+constexpr double MPH_TO_MPS(double a) { return a * kMPSPerMPH;}
 
-/* knots to meters/second */
-constexpr double KNOTS_TO_MPS(double a)  {return KPH_TO_MPS(a) * 1.852; }
+/* knots(nautical miles/hour) to meters/second */
+constexpr double KNOTS_TO_MPS(double a)  {return a * kMPSPerKnot;}
 
 #define MILLI_TO_MICRO(t) ((t) * 1000)  /* Milliseconds to Microseconds */
 #define MICRO_TO_MILLI(t) ((t) / 1000)  /* Microseconds to Milliseconds*/
@@ -518,7 +527,7 @@ public:
   unsigned char cadence;        /* revolutions per minute */
   float power; /* watts, as measured by cyclists */
   float temperature; /* Degrees celsius */
-  float odometer_distance; /* Meters? */
+  float odometer_distance; /* Meters */
   geocache_data* gc_data;
   FormatSpecificDataList fs;
   const session_t* session;    /* pointer to a session struct */
diff --git a/reference/distance.csv b/reference/distance.csv
new file mode 100644 (file)
index 0000000..f51d3db
--- /dev/null
@@ -0,0 +1,7 @@
+lat,lon,alt
+40.0,-105.0,1.0m
+40.0,-105.0,1.0ft
+40.0,-105.0,1.0km
+40.0,-105.0,1.0nm
+40.0,-105.0,1.0mi
+40.0,-105.0,1.0fa
diff --git a/reference/distance2.csv b/reference/distance2.csv
new file mode 100644 (file)
index 0000000..0a57211
--- /dev/null
@@ -0,0 +1,2 @@
+Lat,Lon,Dist(m)
+40.000000,-105.000000,1.0
diff --git a/reference/distance2~csv.csv b/reference/distance2~csv.csv
new file mode 100644 (file)
index 0000000..85ef25a
--- /dev/null
@@ -0,0 +1,2 @@
+Lat,Lon,Dist(m),Dist(mile),Dist(nautical miles)
+40.000000,-105.000000,1.000000e+00,6.213712e-04,5.399568e-04
diff --git a/reference/distance3.csv b/reference/distance3.csv
new file mode 100644 (file)
index 0000000..a8598c9
--- /dev/null
@@ -0,0 +1,3 @@
+UTM
+21N 499500 0
+21N 500500 0
diff --git a/reference/distance3~csv.csv b/reference/distance3~csv.csv
new file mode 100644 (file)
index 0000000..bceb24f
--- /dev/null
@@ -0,0 +1,3 @@
+Utm,Dist(m),Dist(km),Dist(mile),Dist(nautical miles)
+21N 499500       0,0.000000e+00,0.000000e+00,0.000000e+00,0.000000e+00
+21N 500500       0,1.000400e+03,1.000400e+00,6.216198e-01,5.401729e-01
diff --git a/reference/distance~csv.csv b/reference/distance~csv.csv
new file mode 100644 (file)
index 0000000..26bd96c
--- /dev/null
@@ -0,0 +1,7 @@
+Lat,Lon,Alt(m),Alt(ft)
+40.000000,-105.000000,1.000000e+00,3.280840e+00
+40.000000,-105.000000,3.048000e-01,1.000000e+00
+40.000000,-105.000000,1.000000e+03,3.280840e+03
+40.000000,-105.000000,1.852000e+03,6.076115e+03
+40.000000,-105.000000,1.609344e+03,5.280000e+03
+40.000000,-105.000000,1.828800e+00,6.000000e+00
diff --git a/reference/speed.csv b/reference/speed.csv
new file mode 100644 (file)
index 0000000..27a62d2
--- /dev/null
@@ -0,0 +1,6 @@
+lat,lon,speed
+40.0,-105.0,1.0mps
+40.0,-105.0,1.0kmh
+40.0,-105.0,1.0mph
+40.0,-105.0,1.0knot
+
diff --git a/reference/speed~csv.csv b/reference/speed~csv.csv
new file mode 100644 (file)
index 0000000..4d62e6b
--- /dev/null
@@ -0,0 +1,5 @@
+Lat,Lon,Speed(m/s),Speed(km/hr),Speed(mile/hr),Speed(knots)
+40.000000,-105.000000,1.000000e+00,3.600000e+00,2.236936e+00,1.943844e+00
+40.000000,-105.000000,2.777778e-01,1.000000e+00,6.213712e-01,5.399568e-01
+40.000000,-105.000000,4.470400e-01,1.609344e+00,1.000000e+00,8.689762e-01
+40.000000,-105.000000,5.144445e-01,1.852000e+00,1.150780e+00,1.000000e+00
diff --git a/testo.d/unitconversion.test b/testo.d/unitconversion.test
new file mode 100644 (file)
index 0000000..55fb27f
--- /dev/null
@@ -0,0 +1,68 @@
+# This covers conversions to and from various speed units.
+echo 'DESCRIPTION  Speed Test' > speed.style
+echo 'EXTENSION csv' >> speed.style
+echo 'FIELD_DELIMITER COMMA' >> speed.style
+echo 'RECORD_DELIMITER NEWLINE' >> speed.style
+echo 'DATATYPE TRACK' >> speed.style
+echo 'PROLOGUE Lat,Lon,Speed(m/s),Speed(km/hr),Speed(mile/hr),Speed(knots)' >> speed.style
+echo 'OFIELD LAT_DECIMAL,"","%f"' >> speed.style
+echo 'OFIELD LON_DECIMAL,"","%f"' >> speed.style
+echo 'OFIELD PATH_SPEED,"","%.6e"' >> speed.style
+echo 'OFIELD PATH_SPEED_KPH,"","%.6e"' >> speed.style
+echo 'OFIELD PATH_SPEED_MPH,"","%.6e"' >> speed.style
+echo 'OFIELD PATH_SPEED_KNOTS,"","%.6e"' >> speed.style
+
+gpsbabel -t -i unicsv -f ${REFERENCE}/speed.csv -o xcsv,style=speed.style -F ${TMPDIR}/speed~csv.csv
+compare ${REFERENCE}/speed~csv.csv ${TMPDIR}/speed~csv.csv
+
+# This covers distance conversions to meters, but only a couple from meters.
+echo 'DESCRIPTION  Distance Test' > distance.style
+echo 'EXTENSION csv' >> distance.style
+echo 'FIELD_DELIMITER COMMA' >> distance.style
+echo 'RECORD_DELIMITER NEWLINE' >> distance.style
+echo 'DATATYPE TRACK' >> distance.style
+echo 'PROLOGUE Lat,Lon,Alt(m),Alt(ft)' >> distance.style
+echo 'OFIELD LAT_DECIMAL,"","%f"' >> distance.style
+echo 'OFIELD LON_DECIMAL,"","%f"' >> distance.style
+echo 'OFIELD ALT_METERS,"","%.6e"' >> distance.style
+echo 'OFIELD ALT_FEET,"","%.6e"' >> distance.style
+
+gpsbabel -t -i unicsv -f ${REFERENCE}/distance.csv -o xcsv,style=distance.style -F ${TMPDIR}/distance~csv.csv
+compare ${REFERENCE}/distance~csv.csv ${TMPDIR}/distance~csv.csv
+
+# This covers additional distance conversions from meters.
+echo 'DESCRIPTION  Distance 2 Test' > distance2.style
+echo 'EXTENSION csv' >> distance2.style
+echo 'FIELD_DELIMITER COMMA' >> distance2.style
+echo 'RECORD_DELIMITER NEWLINE' >> distance2.style
+echo 'DATATYPE TRACK' >> distance2.style
+echo 'PROLOGUE Lat,Lon,Dist(m),Dist(mile),Dist(nautical miles)' >> distance2.style
+echo 'IFIELD LAT_DECIMAL,"","%f"' >> distance2.style
+echo 'IFIELD LON_DECIMAL,"","%f"' >> distance2.style
+echo 'IFIELD PATH_DISTANCE_METERS,"","%.6e"' >> distance2.style
+echo 'OFIELD LAT_DECIMAL,"","%f"' >> distance2.style
+echo 'OFIELD LON_DECIMAL,"","%f"' >> distance2.style
+echo 'OFIELD PATH_DISTANCE_METERS,"","%.6e"' >> distance2.style
+echo 'OFIELD PATH_DISTANCE_MILES,"","%.6e"' >> distance2.style
+echo 'OFIELD PATH_DISTANCE_NAUTICAL_MILES,"","%.6e"' >> distance2.style
+
+gpsbabel -t -i xcsv,style=distance2.style -f ${REFERENCE}/distance2.csv -o xcsv,style=distance2.style -F ${TMPDIR}/distance2~csv.csv
+compare ${REFERENCE}/distance2~csv.csv ${TMPDIR}/distance2~csv.csv
+
+# This covers xcsv path distances.
+# Reference has points ~1000m apart.
+echo 'DESCRIPTION  Distance 3 Test' > distance3.style
+echo 'EXTENSION csv' >> distance3.style
+echo 'FIELD_DELIMITER COMMA' >> distance3.style
+echo 'RECORD_DELIMITER NEWLINE' >> distance3.style
+echo 'DATATYPE TRACK' >> distance3.style
+echo 'PROLOGUE Utm,Dist(m),Dist(km),Dist(mile),Dist(nautical miles)' >> distance3.style
+echo 'IFIELD UTM,"","%s"' >> distance3.style
+echo 'OFIELD UTM,"","%s"' >> distance3.style
+echo 'OFIELD PATH_DISTANCE_METERS,"","%.6e"' >> distance3.style
+echo 'OFIELD PATH_DISTANCE_KM,"","%.6e"' >> distance3.style
+echo 'OFIELD PATH_DISTANCE_MILES,"","%.6e"' >> distance3.style
+echo 'OFIELD PATH_DISTANCE_NAUTICAL_MILES,"","%.6e"' >> distance3.style
+
+gpsbabel -t -i xcsv,style=distance3.style -f ${REFERENCE}/distance3.csv -o xcsv,style=distance3.style -F ${TMPDIR}/distance3~csv.csv
+compare ${REFERENCE}/distance3~csv.csv ${TMPDIR}/distance3~csv.csv
diff --git a/xcsv.cc b/xcsv.cc
index 4114018ee02dc2d4f30e3e6efcd433bdd006f9af..02eb1ab9ce2d8cc34b10176119710bc64366f90d 100644 (file)
--- a/xcsv.cc
+++ b/xcsv.cc
@@ -51,7 +51,7 @@
 #include "formspec.h"                 // for FormatSpecificDataList
 #include "garmin_fs.h"                // for garmin_fs_t, garmin_fs_alloc
 #include "gbfile.h"                   // for gbfgetstr, gbfclose, gbfopen, gbfile
-#include "grtcirc.h"                  // for RAD, gcdist, radtomiles
+#include "grtcirc.h"                  // for RAD, gcdist, radtometers
 #include "jeeps/gpsmath.h"            // for GPS_Math_WGS84_To_UTM_EN, GPS_Lookup_Datum_Index, GPS_Math_Known_Datum_To_WGS84_M, GPS_Math_UTM_EN_To_Known_Datum, GPS_Math_WGS84_To_Known_Datum_M, GPS_Math_WGS84_To_UKOSMap_M
 #include "jeeps/gpsport.h"            // for int32
 #include "session.h"                  // for session_t
@@ -128,6 +128,7 @@ const QHash<QString, XcsvStyle::xcsv_token> XcsvStyle::xcsv_tokens {
   { "PATH_DISTANCE_KM", XT_PATH_DISTANCE_KM },
   { "PATH_DISTANCE_METERS", XT_PATH_DISTANCE_METERS },
   { "PATH_DISTANCE_MILES", XT_PATH_DISTANCE_MILES },
+  { "PATH_DISTANCE_NAUTICAL_MILES", XT_PATH_DISTANCE_NAUTICAL_MILES },
   { "PATH_SPEED", XT_PATH_SPEED },
   { "PATH_SPEED_KNOTS", XT_PATH_SPEED_KNOTS },
   { "PATH_SPEED_KPH", XT_PATH_SPEED_KPH },
@@ -751,6 +752,9 @@ XcsvFormat::xcsv_parse_val(const QString& value, Waypoint* wpt, const XcsvStyle:
   case XcsvStyle::XT_PATH_DISTANCE_MILES:
     wpt->odometer_distance = MILES_TO_METERS(atof(s));
     break;
+  case XcsvStyle::XT_PATH_DISTANCE_NAUTICAL_MILES:
+    wpt->odometer_distance = NMILES_TO_METERS(atof(s));
+    break;
   case XcsvStyle::XT_HEART_RATE:
     wpt->heartrate = atoi(s);
     break;
@@ -981,8 +985,8 @@ XcsvFormat::xcsv_waypt_pr(const Waypoint* wpt)
   char utmzc;
 
   if (oldlon < 900) {
-    pathdist += radtomiles(gcdist(RAD(oldlat),RAD(oldlon),
-                                  RAD(wpt->latitude),RAD(wpt->longitude)));
+    pathdist += radtometers(gcdist(RAD(oldlat),RAD(oldlon),
+                                   RAD(wpt->latitude),RAD(wpt->longitude)));
   }
   longitude = oldlon = wpt->longitude;
   latitude = oldlat = wpt->latitude;
@@ -1282,7 +1286,15 @@ XcsvFormat::xcsv_waypt_pr(const Waypoint* wpt)
       if (wpt->odometer_distance) {
         buff = QString::asprintf(fmp.printfc.constData(), METERS_TO_MILES(wpt->odometer_distance));
       } else {
-        buff = QString::asprintf(fmp.printfc.constData(), pathdist);
+        buff = QString::asprintf(fmp.printfc.constData(), METERS_TO_MILES(pathdist));
+      }
+      break;
+    case XcsvStyle::XT_PATH_DISTANCE_NAUTICAL_MILES:
+      /* path (route/track) distance in miles */
+      if (wpt->odometer_distance) {
+        buff = QString::asprintf(fmp.printfc.constData(), METERS_TO_NMILES(wpt->odometer_distance));
+      } else {
+        buff = QString::asprintf(fmp.printfc.constData(), METERS_TO_NMILES(pathdist));
       }
       break;
     case XcsvStyle::XT_PATH_DISTANCE_METERS:
@@ -1290,7 +1302,7 @@ XcsvFormat::xcsv_waypt_pr(const Waypoint* wpt)
       if (wpt->odometer_distance) {
         buff = QString::asprintf(fmp.printfc.constData(), wpt->odometer_distance);
       } else {
-        buff = QString::asprintf(fmp.printfc.constData(), MILES_TO_METERS(pathdist));
+        buff = QString::asprintf(fmp.printfc.constData(), pathdist);
       }
       break;
     case XcsvStyle::XT_PATH_DISTANCE_KM:
@@ -1298,7 +1310,7 @@ XcsvFormat::xcsv_waypt_pr(const Waypoint* wpt)
       if (wpt->odometer_distance) {
         buff = QString::asprintf(fmp.printfc.constData(), wpt->odometer_distance / 1000.0);
       } else {
-        buff = QString::asprintf(fmp.printfc.constData(), MILES_TO_METERS(pathdist) / 1000.0);
+        buff = QString::asprintf(fmp.printfc.constData(), pathdist / 1000.0);
       }
       break;
     case XcsvStyle::XT_PATH_SPEED:
diff --git a/xcsv.h b/xcsv.h
index cc07b9fada983215ad8ee408229a786091fce1ac..85f194c060845ce7f97539f7da85c14b88723eef 100644 (file)
--- a/xcsv.h
+++ b/xcsv.h
@@ -118,6 +118,7 @@ public:
     XT_PATH_DISTANCE_KM,
     XT_PATH_DISTANCE_METERS,
     XT_PATH_DISTANCE_MILES,
+    XT_PATH_DISTANCE_NAUTICAL_MILES,
     XT_PATH_SPEED,
     XT_PATH_SPEED_KNOTS,
     XT_PATH_SPEED_KPH,
index 1e89332ab3313848ab9683d643839923dd7f2f49..f18b910d8ed269e3e8c2e937a65947c39b861e37 100644 (file)
@@ -1041,6 +1041,12 @@ longitude)
 </para>
          <screen format="linespecific">PATH_DISTANCE_MILES,&quot;&quot;,&quot;%f&quot;
 </screen>
+      </section>
+      <section id="style_def_pathdistnm">
+         <title>PATH_DISTANCE_NAUTICAL_MILES</title>
+         <para>PATH_DISTANCE_NAUTICAL_MILES is like PATH_DISTANCE_MILES except it outputs the
+   length in nautical miles.
+</para>
       </section>
       <section id="style_def_pathdistkm">
          <title>PATH_DISTANCE_KM</title>